package com.org.cys.code.pdm;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import freemarker.template.Configuration;
import freemarker.template.Template;

/**
 * 代码生层器主类
 * @author caiyushen
 * */
public class FreeMarker{
	
	//生成文件夹的路径
	private static String createFilePath = "D:"+File.separator+"freeMarkerFTL"+File.separator;
	
	//读取模板文件夹的路径
	private static String readFilePath = "D:/EclipseWorkspace/ssm2/src/com/org/cys/code/template";
	
	//读取powerDesigner文件的路径
	private static String pdmFilePath = "D:\\EclipseWorkspace\\ssm2\\doc\\ssm.pdm";
	
	//生成单表文件还是中间表文件（根据表的id字段判断） true:单表  false:中间表
	private static boolean oneFlag;
	
	//测试方法
	public static void main(String[] args) {
		Parser parser = new Parser();
		try {
			//读取pdm文件
			PDM pdm = parser.pdmParser(pdmFilePath);
			//获取表的数据
			ArrayList<PDMTable> pdmTableList = pdm.getTables();
			int pdmTableListSize = pdmTableList.size();
			//遍历所有表数据
			for(int i=0;i<pdmTableListSize;i++){
				//获取一个表数据
				PDMTable pdmTable = pdmTableList.get(i);
				List<PDMColumn> columnList = pdmTable.getColumns();
				for(PDMColumn column : columnList){
					oneFlag = false;
					System.out.println("column:" + column.getCode());
					if(column.getCode().equals("id")){//生成单表文件还是中间表文件（根据表的id字段判断）
						oneFlag = true;
						break;
					}
				}
				System.out.println("oneFlag: "+oneFlag);
				//获取模块-包名
				String packageName = getPackageName(pdmTable);
				//获取实体类名
				String entityName = switchEntityName(pdmTable);
				getMapperXml(pdmTable,entityName,packageName);
				getService(pdmTable,entityName,packageName);
				getServiceImpl(pdmTable,entityName,packageName);
				getTestService(pdmTable,entityName,packageName);
				getController(pdmTable,entityName,packageName);
				getListJSP(pdmTable,entityName,packageName);
				getListJavaScript(pdmTable,entityName,packageName);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 通过文件名加载模板
	 * @param ftlName 模板文件名
	 * @param ftlPath 模板路径
	 * */
	public static Template getTemplate(String ftlName,String ftlPath) throws Exception{
		try {
			Configuration cfg = new Configuration();  	//通过Freemaker的Configuration读取相应的ftl
			cfg.setEncoding(Locale.CHINA, "utf-8");
			cfg.setDirectoryForTemplateLoading(new File(ftlPath));	//设定去哪里读取相应的ftl模板文件
			Template temp = cfg.getTemplate(ftlName);	//在模板文件目录中找到名称为name的文件
			return temp;
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		return null;
	}
	

	/**
	 * 将table的字段数据转化变量数据
	 * @param pdmTable 单表数据
	 * @author caiyushen
	 * */
	public static List<Map<String,Object>> switchTable(PDMTable pdmTable){
		//获取该表所有字段数据
		ArrayList<PDMColumn> columnsList = pdmTable.getColumns();
		//System.out.println("表内字段数目: " + columnsList.size());
		//System.out.println("注释里表名: "+pdmTable.getName());
		//System.out.println("表名: "+pdmTable.getCode());
		List<Map<String,Object>> dataList = new ArrayList();
		for(int i=0;i<columnsList.size();i++){
			//获取一个字段数据
			PDMColumn column = columnsList.get(i);
			//System.out.println("注释："+column.getComment());	
			//System.out.println("类型："+column.getDataType());
			//将字段名转化为变量名
			String newColumn = switchColumn(column);	
			Map<String,Object> resultMap = new HashMap<>();
			resultMap.put("newColumn", newColumn);  //新变量 parent_id --> parentId
			resultMap.put("comment", column.getComment()); //字段注释
			resultMap.put("newColumnBigger",switchColumnBigger(column));//parent_id --> ParentId
			resultMap.put("midEntity", switchColumnEntity(column)); //user_id --> User , good_cat_id -->Good
			resultMap.put("midEntitySmall", switchColumnEntitySmall(column)); //user_id --> user , good_cat_id -->good
			resultMap.put("dataType",switchObject(column)); //字段类型
			resultMap.put("columnName", column.getName()); //数据库字段名字
			System.out.println("resultMap : " + resultMap.toString());
			dataList.add(resultMap);
		}
		return dataList;
	}
	
	/**
	 * 生成模板文件
	 * @param file 新增的文件名以及路径
	 * @param template 指定的模板文件
	 * @param pdmTable 数据库表实体类
	 * @param packageName 包名-模块名
	 * @param entityName 实体类名称
	 * */
	public static void getFile(File file,Template template,PDMTable pdmTable,String packageName,String entityName){
		try {
			List<Map<String,Object>> dataList = switchTable(pdmTable);
			Map<String, Object> context = new HashMap<String, Object>();
			context.put("entityName", entityName);
			context.put("entityNameSmall", switchEntityNameSmall(pdmTable));
			context.put("entityComment", pdmTable.getName());
			context.put("tableName", pdmTable.getCode());//数据库表名
			context.put("dataList", dataList);
			context.put("package", packageName);//包名-模块名
			Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), "utf-8"));
			template.process(context, out);
	        out.flush();
	        out.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	
	
	/**
	 * 生成XML文件
	 * @param pdmTable 数据库表实体类
	 * @param packageName 包名-模块名
	 * */
	public static void getMapperXml(PDMTable pdmTable,String entityName,String packageName){
		try {
			//创建文件夹
			createDir(entityName);
			File file = new File(createFilePath+entityName+File.separator+entityName+"Mapper.xml");
			Template template;//指定模板
			if(oneFlag){
				System.out.println("生成单表文件");
				template = getTemplate("XMLMarker.ftl",readFilePath);//单表
			}else{
				System.out.println("生成中间表文件");
				template = getTemplate("MidXMLMarker.ftl",readFilePath);
			}
			
			//生成文件
			getFile(file,template,pdmTable,packageName,entityName);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 生成Service接口
	 * @param pdmTable 数据库表实体类
	 * @param packageName 包名-模块名
	 * */
	public static void getService(PDMTable pdmTable,String entityName,String packageName){
		try {
			//创建文件夹
			createDir(entityName);
			File file = new File(createFilePath+entityName+File.separator+entityName+"Service.java");
			Template template;//指定模板
			if(oneFlag){
				template = getTemplate("ServiceMarker.ftl",readFilePath);//单表
			}else{
				template = getTemplate("MidServiceMarker.ftl",readFilePath);
			}
			//生成文件
			getFile(file,template,pdmTable,packageName,entityName);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	
	/**
	 * 生成Service实体类
	 * @param pdmTable 数据库表实体类
	 * @param packageName 包名-模块名
	 * */
	public static void getServiceImpl(PDMTable pdmTable,String entityName,String packageName){
		try {
			//创建文件夹
			createDir(entityName);
			File file = new File(createFilePath+entityName+File.separator+entityName+"ServiceImpl.java");
			Template template;//指定模板
			if(oneFlag){
				template = getTemplate("ServiceImplMarker.ftl",readFilePath);//单表
			}else{
				template = getTemplate("MidServiceImplMarker.ftl",readFilePath);
			}
			//生成文件
			getFile(file,template,pdmTable,packageName,entityName);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 生成Service单元测试
	 * @param pdmTable 数据库表实体类
	 * @param packageName 包名-模块名
	 * */
	public static void getTestService(PDMTable pdmTable,String entityName,String packageName){
		try {
			//创建文件夹
			createDir(entityName);
			File file = new File(createFilePath+entityName+File.separator+entityName+"ServiceTest.java");
			Template template;//指定模板
			if(oneFlag){
				template = getTemplate("TestServiceMarker.ftl",readFilePath);//单表
			}else{
				template = getTemplate("MidTestServiceMarker.ftl",readFilePath);;
			}
			
			//生成文件
			getFile(file,template,pdmTable,packageName,entityName);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	
	/**
	 * 生成Controller
	 * @param pdmTable 数据库表实体类
	 * @param packageName 包名-模块名
	 * */
	public static void getController(PDMTable pdmTable,String entityName,String packageName){
		try {
			//创建文件夹
			createDir(entityName);
			File file = new File(createFilePath+entityName+File.separator+entityName+"Controller.java");
			Template template;//指定模板
			if(oneFlag){
				template = getTemplate("ControllerMarker.ftl",readFilePath);//单表
				//生成文件
				getFile(file,template,pdmTable,packageName,entityName);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 生成列表JSP文件
	 * @param pdmTable 数据库表实体类
	 * @param packageName 包名-模块名
	 * */
	public static void getListJSP(PDMTable pdmTable,String entityName,String packageName){
		try {
			//创建文件夹
			createDir(entityName);
			File file = new File(createFilePath+entityName+File.separator+"list.jsp");
			Template template;//指定模板
			if(oneFlag){
				template = getTemplate("ListJSPMarker.ftl",readFilePath);//单表
				//生成文件
				getFile(file,template,pdmTable,packageName,entityName);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 生成列表js文件
	 * */
	public static void getListJavaScript(PDMTable pdmTable,String entityName,String packageName){
		try {
			//创建文件夹
			createDir(entityName);
			File file = new File(createFilePath+entityName+File.separator+"list.js");
			Template template;//指定模板
			if(oneFlag){
				template = getTemplate("ListJavaScriptMarker.ftl",readFilePath);//单表
				//生成文件
				getFile(file,template,pdmTable,packageName,entityName);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 根据数据表字段类型转换为对应封装的JAVA类型
	 * int、bigint --> Integer  
	 * varchar、text --> String
	 * date、datetime  --> Date
	 * */
	public static String switchObject(PDMColumn column){
		String resultObj = "";
		String dataType = column.getDataType();
		System.out.println("dataType: "+dataType);
		
		if(dataType.contains("bigint")){//long
			resultObj = "Long";
			return resultObj;
		}
		
		if(dataType.contains("int")){//int
			resultObj = "Integer";
			return resultObj;
		}
		
		if(dataType.contains("varchar")||dataType.contains("text")){///text varchar
			resultObj = "String";
			return resultObj;
		}
	
		if(dataType.contains("date") || dataType.contains("datetime")){//datetime date
			resultObj = "Date";
			return resultObj;
		}
		
		return resultObj;
	}
	
	/**
	 * 将数据表名转化为实体类名
	 * 取最后的作为实体类名
	 * t_system_user --> User
	 * */
	public static String switchEntityName(PDMTable pdmTable){
		String tableName = pdmTable.getCode();
		String[] array = tableName.split("_");
		String newCode = "";
		for(int i=0;i<array.length;i++){
			if(i>1){
				char[] c= array[i].toCharArray();
				String replaceCode = "";
				for(int j=0;j<c.length;j++){
					if(j>0){
						replaceCode += c[j];
					}
				}
				newCode += Character.toUpperCase(c[0])+ replaceCode;//将第一个字符变成大写
			}
		}
		System.out.println("switchEntityName 实体类名："+newCode);
		return newCode;
	}
	
	/**
	 * 将数据表名转化为小写实体类名
	 * 取最后的作为实体类名
	 * t_system_user --> user
	 * t_system_user_app --> userApp
	 * */
	public static String switchEntityNameSmall(PDMTable pdmTable){
		String tableName = pdmTable.getCode();
		String[] array = tableName.split("_");
		String newCode = "";
		for(int i=0;i<array.length;i++){
			if(i>1){
				char[] c= array[i].toCharArray();
				String replaceCode = "";
				for(int j=0;j<c.length;j++){
					if(j>0){
						replaceCode += c[j];
					}
				}
				if(i==2){
					newCode += c[0]+ replaceCode;//取原来的表名,即例子中的user
				}else{
					newCode += Character.toUpperCase(c[0])+ replaceCode;//将第一个字符变成大写
				}
				
			}
		}
		System.out.println("switchEntityNameSmal 小写实体类名："+newCode);
		return newCode;
	}
	
	
	/**
	 * 把数据表字段转化为变量名
	 * create_date --> createDate
	 * */
	public static String switchColumn(PDMColumn column){
		String newCode = "";
		String[] array = column.getCode().split("_");
		for(int i=0;i<array.length;i++){
			if(i>0){
				char[] c= array[i].toCharArray();
				String replaceCode = "";
				for(int j=0;j<c.length;j++){
					if(j>0){
						replaceCode += c[j];
					}
				}
				newCode += Character.toUpperCase(c[0]) + replaceCode;
			}else{
				newCode += array[i];
			}
		}
		System.out.println("switchColumn 转换后的新变量："+newCode);
		return newCode;
	}
	
	/**
	 * 把数据表字段转化为变量名
	 * user_id --> UserId
	 * */
	public static String switchColumnBigger(PDMColumn column){
		String newCode = "";
		String[] array = column.getCode().split("_");
		for(int i=0;i<array.length;i++){
			char[] c= array[i].toCharArray();
			String replaceCode = "";
			for(int j=0;j<c.length;j++){
				if(j>0){
					replaceCode += c[j];
				}
			}
			newCode += Character.toUpperCase(c[0]) + replaceCode;
		}
		System.out.println("switchColumnBigger 转换后的新变量："+newCode);
		return newCode;
	}
	
	/**
	 * 根据关联id转化为实体类
	 * user_id --> User
	 * create_date --> Create
	 * good_student_id --> Good
	 * */
	public static String switchColumnEntity(PDMColumn column){
		String newCode = "";
		String[] array = column.getCode().split("_");
		if(array.length>0){
			char[] c= array[0].toCharArray();
			String replaceCode = "";
			for(int j=0;j<c.length;j++){
				if(j>0){
					replaceCode += c[j];
				}
			}
			newCode += Character.toUpperCase(c[0]) + replaceCode;
		}
		System.out.println("switchColumnEntity 转换后的新变量："+newCode);
		return newCode;
	}
	
	/**
	 * 根据关联id转化为实体类变量
	 * user_id --> user
	 * create_date --> create
	 * good_student_id --> good
	 * */
	public static String switchColumnEntitySmall(PDMColumn column){
		String newCode = "";
		String[] array = column.getCode().split("_");
		newCode = array[0];
		System.out.println("switchColumnEntitySmall 转换后的新变量："+newCode);
		return newCode;
	}
	
	/**
	 * 把一个字符串中的大写转为小写,小写转大写
	 * */
	public static String exChange(String str){  
	    StringBuffer sb = new StringBuffer();  
	    if(str!=null){  
	        for(int i=0;i<str.length();i++){  
	            char c = str.charAt(i);  
	            if(Character.isUpperCase(c)){  
	                sb.append(Character.toLowerCase(c));  
	            }else if(Character.isLowerCase(c)){  
	                sb.append(Character.toUpperCase(c));   
	            }  
	        }  
	    }  
	    return sb.toString();  
	}  
	
	/**
	 * 获取模块名称即获取表名的第二个字段名称
	 * */
	public static String getPackageName(PDMTable pdmTable){
		String result = "";
		String[] array = pdmTable.getCode().split("_");
		if(array.length>2){
			result = array[1];
		}
		System.out.println("getPackageName 模块名称："+result);
		return result;
	}
	
	
	
	/**
	 * 创建文件夹
	 * */
	public static void createDir(String entityName){
		//判断文件夹是否存在，不存在则创建该文件夹
		File wordFile =new File(createFilePath+entityName);//文件夹    
		//如果文件夹不存在则创建    
		if(!wordFile .exists()&&!wordFile .isDirectory()){       
		    System.out.println("文件不存在，创建该文件夹");  
		    wordFile .mkdir();    
		}
	}
	
}